#include "fxcc/core/graph/opengl3/MeshJack.h"
#include "fxcc/core/graph/opengl3/RenderStates.h"

fxcc::graph::opengl3::MeshJack::MeshJack(const fxcc::graph::common::GeometryData& geoData, const fxcc::graph::common::SkinnedMeshData& skinnedMeshData)
    : fxcc::graph::common::MeshJack(common::MeshJack::Desc(geoData, skinnedMeshData))
{
    VertexArray::Create();
    VertexArray::Bind();
    m_IndexBuffer.Bind();
    m_IndexBuffer.BufferData<unsigned int>(geoData.indices32);
    LoadSkinnedMeshBuffers(geoData, skinnedMeshData);

    m_IndexType = fxcc::graph::common::IndexType::_index_unsigned_int_;
    m_VertexType = fxcc::graph::common::VertexType::_vertex_skinned_;
    m_ModeType = fxcc::graph::common::ModeType::_mode_Triangles_;
    m_NumIndices = geoData.indices32.size();
    m_NumVertices = geoData.vertices.size();

    OnEndCreate();

}


fxcc::graph::opengl3::MeshJack::MeshJack(const fxcc::graph::common::GeometryData& geoData)
    : fxcc::graph::common::MeshJack(fxcc::graph::common::MeshJack(geoData))
{
    VertexArray::Create();
    VertexArray::Bind();
    m_IndexBuffer.Bind();
    m_IndexBuffer.BufferData<unsigned int>(geoData.indices32);
    LoadFixedMeshBuffersFrom(geoData);

    m_IndexType = fxcc::graph::common::IndexType::_index_unsigned_int_;
    m_VertexType = fxcc::graph::common::VertexType::_vertex_fixed_;
    m_ModeType = fxcc::graph::common::ModeType::_mode_Triangles_;
    m_NumIndices = geoData.indices32.size();
    m_NumVertices = geoData.vertices.size();

    OnEndCreate();
};

void fxcc::graph::opengl3::MeshJack::LoadMSDFBuffersFrom(const fxcc::graph::common::MSDFGeoData& geoData)
{
    m_VertexBuffers.resize(2);
    int index = 0;

    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.vertices);
        SetVertexBufferIndexFloat<glm::vec2>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.texCoords);
        SetVertexBufferIndexFloat<glm::vec2>(index, false);
        index++;

    }
}

void fxcc::graph::opengl3::MeshJack::LoadSDFBuffersFrom(const fxcc::graph::common::SDFGeoData& geoData)
{
    m_VertexBuffers.resize(3);
    int index = 0;

    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.vertices);
        SetVertexBufferIndexFloat<glm::vec2>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<unsigned int>(geoData.pageIndices);
        SetVertexBufferIndexInteger<unsigned int>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.texCoords);
        SetVertexBufferIndexFloat<glm::vec2>(index, true);
        index++;
    }
  
}

void fxcc::graph::opengl3::MeshJack::LoadFixedMeshBuffersFrom(const fxcc::graph::common::GeometryData& geoData)
{
    m_VertexBuffers.resize(5);

    int index = 0;
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.vertices);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.normals);
        SetVertexBufferIndexFloat<glm::vec3>(index, true);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.texcoords);
        SetVertexBufferIndexFloat<glm::vec2>(index, false);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.tangents);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.bigTangents);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }
};

void fxcc::graph::opengl3::MeshJack::LoadSkinnedMeshBuffers(const fxcc::graph::common::GeometryData& geoData, const fxcc::graph::common::SkinnedMeshData& skinnedMeshData)
{
    m_VertexBuffers.resize(9);

    int index = 0;
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.vertices);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.normals);
        SetVertexBufferIndexFloat<glm::vec3>(index, true);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec2>(geoData.texcoords);
        SetVertexBufferIndexFloat<glm::vec2>(index, false);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.tangents);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec3>(geoData.bigTangents);
        SetVertexBufferIndexFloat<glm::vec3>(index, false);
        index++;
    }

    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::ivec4>(skinnedMeshData.bones1s);
        SetVertexBufferIndexInteger<glm::ivec4>(index );
        index++;
    };
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec4>(skinnedMeshData.weights1s);
        SetVertexBufferIndexFloat<glm::vec4>(index, false);
        index++;
    }
    {
        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::ivec4>(skinnedMeshData.bones2s);
        SetVertexBufferIndexInteger<glm::ivec4>(index);
        index++;
    };
    {

        auto& buffer = m_VertexBuffers[index];
        buffer.Bind();
        buffer.BufferData<glm::vec4>(skinnedMeshData.weights2s);
        SetVertexBufferIndexFloat<glm::vec4>(index , false);
        index++;
    }
}

fxcc::graph::opengl3::MeshJack::MeshJack(const fxcc::graph::common::MSDFGeoData& geoData)
   : fxcc::graph::common::MeshJack(common::MeshJack::Desc(geoData))

{
    VertexArray::Create();
    VertexArray::Bind();
    m_IndexBuffer.Bind();
    m_IndexBuffer.BufferData<unsigned int>(geoData.indices32);
    LoadMSDFBuffersFrom(geoData);

    m_IndexType = fxcc::graph::common::IndexType::_index_unsigned_int_;
    m_VertexType = fxcc::graph::common::VertexType::_vertex_font_;
    m_ModeType = fxcc::graph::common::ModeType::_mode_Triangles_;
    m_NumIndices = geoData.indices32.size();
    m_NumVertices = geoData.vertices.size();

    OnEndCreate();
}


void fxcc::graph::opengl3::MeshJack::DrawElementsAuto() const
{
    const auto& modeDesc = RenderStates::Inst().GetModeDesc(m_ModeType);
    const auto& indexDesc = RenderStates::Inst().GetIndexDesc(m_IndexType);

    VertexArray::DrawElements(modeDesc.m_Target, m_NumIndices, indexDesc.m_Target, 0);
};


void fxcc::graph::opengl3::MeshJack::OnEndCreate()
{
    fxcc::graph::opengl3::VertexArray::UnBind();
    fxcc::graph::opengl3::IndexBuffer::UnBind();
    fxcc::graph::opengl3::VertexBuffer::UnBind();
    m_Desc.Clear();

}
;
